﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Threading;

namespace Smash
{
    public partial class Dashboard : Form
    {
        public override string Text
        {
            get
            {
                return base.Text;
            }
            set
            {
                if (value == null)
                {
                    base.Text = "SmashBoard";
                }
                else
                {
                    base.Text = "SmashBoard : " + value;
                }
            }
        }

        public static IPHostEntry HostEntry
        {
            get
            {
                return System.Net.Dns.GetHostEntry(
                         System.Net.Dns.GetHostName());
            }
        }

        public IPAddress MyIP
        {
            get
            {
                return System.Net.Dns.GetHostEntry(
                         System.Net.Dns.GetHostName())
                       .AddressList[0];
            }
        }

        public Dashboard()
        {
            InitializeComponent();

            OnUpdateImage += Dashboard_OnUpdateImage;
            OnVideoError += Dashboard_OnVideoError;
            OnDataReceived += Dashboard_OnDataReceived;

            StartImageUpdate = DateTime.Now;
        }

        private void Receiver_OnUpdateImage()
        {
            Invoke(OnUpdateImage);
        }

        private void Dashboard_OnUpdateImage()
        {
            if (Receiver.VideoImage == null)
            {
                VideoServerStatus = "Waiting";
            }
            else
            {
                picVideo.Image = Receiver.VideoImage;
                Receiver.VideoImage = null;
                ++ImageUpdateCount;
                LastImageUpdate = DateTime.Now;
                if ((LastImageUpdate - StartImageUpdate).Seconds >= 1)
                {
                    VideoServerStatus = "FPS : " + ImageUpdateCount;
                    ImageUpdateCount = 0;
                    StartImageUpdate = DateTime.Now;
                }
            }
        }

        private void Receiver_OnVideoError(string message)
        {
            Invoke(OnVideoError, message);
        }

        private void Dashboard_OnVideoError(string message)
        {
            lblVideoStatusBar.Text = message;
        }

        private void Receiver_OnDataReceived(int received)
        {
            Invoke(OnDataReceived, received);
        }

        private void Dashboard_OnDataReceived(int received)
        {
            double difference = (DateTime.Now - LastDataUpdate).TotalMilliseconds;
            DataReceivedCount += received;
            if (difference >= 1000.0)
            {
                double kbs = (double)DataReceivedCount / 1024.0;
                kbs = Math.Round(kbs, 2);
                if (kbs < 1)
                {
                    kbs = 0;
                }
                lblNetUsageBar.Text = kbs + " kbs";
                DataReceivedCount = 0;
                LastDataUpdate = DateTime.Now;
            }
        }

        private void Dashboard_FormClosed(object sender, FormClosedEventArgs e)
        {
            if (Receiver != null)
            {
                Receiver.Dispose();
            }
        }

        private void Dashboard_Load(object sender, EventArgs e)
        {
            foreach(IPAddress address in HostEntry.AddressList)
            {
                ddlNetInterfaceMenu.Items.Add(address.ToString());
            }
            ddlResolution.SelectedIndex = 0;
        }

        public void Dashboard_UnhandledException(object sender,
                                                 UnhandledExceptionEventArgs e)
        {
            MessageBox.Show(e.ExceptionObject.ToString());
        }

        public void Dashboard_ThreadException(object sender, 
                                              ThreadExceptionEventArgs e)
        {
            MessageBox.Show(e.Exception.ToString());
        }

        private void tmrTimeoutCheck_Tick(object sender, EventArgs e)
        {
            if ((DateTime.Now - LastImageUpdate).TotalMilliseconds >= 250)
            {
                VideoServerStatus = "Waiting";
                if ((DateTime.Now - LastDataUpdate).TotalMilliseconds >= 1000)
                {
                    lblNetUsageBar.Text = "0 kbs";
                }
            }
        }

        private void ddlNetInterfaceMenu_SelectedIndexChanged(object sender, EventArgs e)
        {
            try
            {
                Text = (string)ddlNetInterfaceMenu.SelectedItem;
                if (Receiver != null)
                {
                    Receiver.Dispose();
                }
                Receiver = new VideoReceiver(IPAddress.Parse(
                                               (string)ddlNetInterfaceMenu
                                                 .SelectedItem),
                                               1234);
                Receiver.OnImageUpdated += Receiver_OnUpdateImage;
                Receiver.OnVideoError += Receiver_OnVideoError;
                Receiver.OnDataReceived += Receiver_OnDataReceived;
                Receiver.Start();
            }
            catch (Exception ex)
            {
            }
        }
        
        private void ddlResolution_SelectedIndexChanged(object sender, EventArgs e)
        {
            // Default 0
            // 160x120 1
            // 320x240 2
            // 480x360 3
            // 640x480 4
            switch (ddlResolution.SelectedIndex)
            {
                case 1:
                    picVideo.Size = new Size(160, 120);
                    picVideo.SizeMode = PictureBoxSizeMode.StretchImage;
                    break;
                case 2:
                    picVideo.Size = new Size(320, 240);
                    picVideo.SizeMode = PictureBoxSizeMode.StretchImage;
                    break;
                case 3:
                    picVideo.Size = new Size(480, 360);
                    picVideo.SizeMode = PictureBoxSizeMode.StretchImage;
                    break;
                case 4:
                    picVideo.Size = new Size(640, 480);
                    picVideo.SizeMode = PictureBoxSizeMode.StretchImage;
                    break;
                default:
                    picVideo.Size = new Size(160, 120);
                    picVideo.SizeMode = PictureBoxSizeMode.AutoSize;
                    break;
            }
        }

        private void btnRestart_Click(object sender, EventArgs e)
        {
            ddlNetInterfaceMenu_SelectedIndexChanged(null, null);
        }

        private int ImageUpdateCount
        {
            get;
            set;
        }

        private int DataReceivedCount
        {
            get;
            set;
        }

        private string VideoServerStatus
        {
            get
            {
                return lblVideoStatus.Text;
            }
            set
            {
                if (value == null)
                {
                    lblVideoStatus.Text = "Status : Waiting";
                }
                else
                {
                    lblVideoStatus.Text = "Status : " + value;
                }
            }
        }

        private DateTime StartImageUpdate
        {
            get;
            set;
        }

        private DateTime LastImageUpdate
        {
            get;
            set;
        }

        private DateTime LastDataUpdate
        {
            get;
            set;
        }

        private VideoReceiver Receiver
        {
            get;
            set;
        }

        private delegate void UpdateImage();
        private event UpdateImage OnUpdateImage;
        private delegate void VideoError(string message);
        private event VideoError OnVideoError;
        private delegate void DataReceived(int message);
        private event DataReceived OnDataReceived;
    }
}
